home *** CD-ROM | disk | FTP | other *** search
/ Aminet 39 / Aminet 39 (2000)(Schatztruhe)[!][Oct 2000].iso / Aminet / util / misc / cookietool.lha / cookietool / cookietool.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-07-17  |  13.3 KB  |  508 lines

  1. /*
  2.     cookietool is (c) 1995-2000 by Wilhelm Noeker (wnoeker@t-online.de)
  3.  
  4.     This program is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU General Public License as
  6.     published by the Free Software Foundation; either version 2 of the
  7.     License, or (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful, but
  10.     WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12.     General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  17.     02111-1307 USA
  18.  
  19.  */
  20.  
  21.  
  22. /*========================================================================*\
  23.  |  File: cookietool.c                                 Date: 25 Oct 1997  |
  24.  *------------------------------------------------------------------------*
  25.  |             Remove duplicate entries from a cookie file,               |
  26.  |                various options for sorting the output.                 |
  27.  | Expected file format is plain text with a "%%" line ending each cookie.|
  28.  |                     See help() for usage notes.                        |
  29.  |                                                                        |
  30. \*========================================================================*/
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <ctype.h>
  36. #include "strstuff.h"
  37.  
  38. char version[] = "$VER: cookietool 2.3 (17.07.2000)";
  39. #define EOC "%%"                /* the cookie delimiter */
  40.  
  41.  
  42. struct cookie
  43.   {
  44.     UBYTE *text;
  45.     UBYTE *sorthook;
  46.     long size;
  47.     long number;
  48.   };
  49.  
  50. struct cookie *clist;
  51.  
  52. long listsize = 1000;           /* will be adjusted dynamically */
  53. long listed = 0;
  54.  
  55. #define FBUFSIZE 16384          /* we'll use larger file buffers */
  56. #define CBUFSIZE 32000L
  57. #define LBUFSIZE 2000
  58. UBYTE cbuf[ CBUFSIZE ];         /* large enough to hold one complete cookie */
  59. UBYTE line[ LBUFSIZE ];         /* large enough to hold the longest line */
  60.  
  61.  
  62.  
  63. /*
  64.  * Print a help text and nag about illegal parameter <s> 
  65.  */
  66. void help( UBYTE *s )
  67. {
  68.   if( s )
  69.     printf( "illegal option '%s'\n", s );
  70.   printf( "usage:  cookietool [ options ] <database> \n" );
  71.   printf( "where options are:\n" );
  72.   printf( " -p      passive, don't delete anything\n" );
  73.   printf( " -a      treat 'abbreviations' as doubles (i.e. delete them, too)\n" );
  74.   printf( " -s      sort cookies\n" );
  75.   printf( " -sl      \" , looking at the last line only\n" );
  76.   printf( " -sw      \" , looking at the last word only\n" );
  77.   printf( " -s<sep>  \" , starting after the last <sep>, e.g. '-s--'\n" );
  78.   printf( " -ss      \" , by size\n" );
  79.   printf( " -d[ 0-3 ] how fussy about word delimiters? (default: 2)\n" );
  80.   printf( " -c      case sensitive comparisons\n" );
  81.   printf( " -o      overwrite directly, no tempfile (caution!)\n" );
  82. }
  83.  
  84.     
  85.  
  86. int cookie_cmp( struct cookie *a, struct cookie *b, int mode )
  87. {
  88.   int c = 0;
  89.  
  90.   switch( mode )
  91.     {
  92.     case 0:                     /* by number */
  93.       c = a->number - b->number;
  94.       break;
  95.     case 1: case -1:            /* by name, ascending/descending */
  96.       c = str_cmp( a->sorthook, b->sorthook );
  97.       if( c == 0 )              /* when in doubt, the number decides */
  98.         c = a->number - b->number;
  99.       c *= mode;
  100.       break;
  101.     case 2:                     /* by size */
  102.       c = a->size - b->size;
  103.       break;
  104.     }
  105.   return c;
  106. }
  107.  
  108.  
  109.  
  110. /* 
  111.  * sift: centre routine to heapsort()
  112.  */
  113. void sift( struct cookie v[], long i, long m, int mode )
  114. {
  115.   long j;
  116.   struct cookie temp;
  117.  
  118.   while( (j = 2 * (i + 1) - 1) <= m )
  119.     {
  120.       if( j < m && cookie_cmp( &v[ j ], &v[ j + 1 ], mode ) < 0 )
  121.         j++;
  122.       if( cookie_cmp( &v[ i ], &v[ j ], mode ) < 0 )
  123.         {
  124.           temp = v[ i ];
  125.           v[ i ] = v[ j ];
  126.           v[ j ] = temp;
  127.           i = j;
  128.         }
  129.       else
  130.         i = m;              /* done */
  131.     }
  132. }
  133.  
  134.  
  135. void my_heapsort( struct cookie v[], long n, int mode )
  136. {
  137.   long i;
  138.   struct cookie temp;
  139.  
  140.   if( n < 2 )                   /* no sorting necessary */
  141.     return;
  142.   for( i = n/2 - 1; i >= 0; i-- )
  143.     sift( v, i, n - 1, mode );
  144.   for( i = n - 1; i >= 1; i-- )
  145.     {
  146.       temp = v[ 0 ];
  147.       v[ 0 ] = v[ i ];
  148.       v[ i ] = temp;
  149.       sift( v, 0, i - 1, mode );
  150.     }
  151. }
  152.  
  153.  
  154. UBYTE hooktarget[ 16 ];
  155.  
  156. void set_hooks( int mode )
  157. /* adjust sorthooks for the final sort, according to the desired mode */
  158. {
  159.   long l;
  160.   int hot;
  161.   UBYTE *s;
  162.  
  163.   printf( "Adjusting sort hooks" );
  164.   fflush( stdout );
  165.   for( l = 0; l < listed; l++ )
  166.     {
  167.       s = clist[ l ].text;
  168.       switch( mode )
  169.         {
  170.         case 3:         /* start of last line */
  171.           hot = 1;
  172.           while( *s )
  173.             {
  174.               if( *s == '\n' )
  175.                 hot = 1;
  176.               else if( hot )
  177.                 {
  178.                   clist[ l ].sorthook = s;
  179.                   hot = 0;
  180.                 }
  181.               s++;
  182.             }
  183.           break;
  184.         case 4:         /* start of last word */
  185.           hot = 1;
  186.           while( *s )
  187.             {
  188.               if( isspace( *s ) )
  189.                 hot = 1;
  190.               else if( hot )
  191.                 {
  192.                   clist[ l ].sorthook = s;
  193.                   hot = 0;
  194.                 }
  195.               s++;
  196.             }
  197.           break;
  198.         case 5:         /* at last occurence of <hooktarget> */
  199.           while( s )
  200.             {
  201.               clist[ l ].sorthook = s++;
  202.               s = strstr( s, hooktarget );
  203.             }
  204.           break;
  205.         default:
  206.         }
  207.     }
  208.   printf( ", done.\n" );
  209. }
  210.  
  211.  
  212.  
  213. /* 
  214.  * Delete cookies and log them to a file
  215.  */
  216. void one_cookie( int doubles, int abbrevs, int finalsort, FILE *fp )
  217. {
  218.   long i, j, dbl = 0, abr = 0;
  219.   int c;
  220.  
  221.   if( doubles )
  222.     {
  223.       printf( "Removing double entries" );
  224.       if( abbrevs )
  225.         printf( " + 'abbreviations'" );
  226.       fflush( stdout );
  227.       my_heapsort( clist, listed, -1 ); /* sort descending by string */
  228.       for( i = listed - 1; i > 0; i = j )
  229.         {
  230.           for( j = i - 1; j >= 0
  231.           && ( (c = str_cmp( clist[ j ].text, clist[ i ].text )) == 0
  232.             || (abbrevs && c == STR_SHORTER) ); j-- )
  233.             {
  234.               if( fp )
  235.                 if( fprintf( fp, "%s\n%s\n", clist[ j ].text, EOC ) <= 0 )
  236.                   {
  237.                     printf( "\nFile error, aborted !!!\n" );
  238.                     exit( 20 );
  239.                   }
  240.               free( clist[ j ].text );
  241.               clist[ j ] = clist[ --listed ];
  242.               if( c == 0 )
  243.                 dbl++;
  244.               else
  245.                 abr++;
  246.             }
  247.         }
  248.       printf( ", done. (%ld + %ld found)\n", dbl, abr );
  249.     }
  250.   if( finalsort > 0 )
  251.     {
  252.       if( finalsort > 2 )
  253.         set_hooks( finalsort );
  254.       printf( "Sorting" );
  255.       fflush( stdout );
  256.       if( finalsort == 2 )
  257.         my_heapsort( clist, listed, 2 );  /* sort by size */
  258.       else
  259.         my_heapsort( clist, listed, 1 );  /* sort ascending by string */
  260.     }                 
  261.   else
  262.     {
  263.       printf( "Restoring order" );
  264.       fflush( stdout );
  265.       my_heapsort( clist, listed, 0 );  /* sort by number */
  266.     }
  267.   printf( ", done.\n" );
  268. }
  269.  
  270.  
  271. void read_cookies( FILE *fp )
  272. {
  273.   long cbuflen, ignored = 0;
  274.   int lines;
  275.  
  276.   printf( "Reading cookies" );
  277.   fflush( stdout );
  278.   strcpy( cbuf, "" );
  279.   lines = 0;
  280.   cbuflen = 0;
  281.   while( fgets( line, LBUFSIZE, fp ) )
  282.     {
  283.       if( strncmp( line, EOC, strlen( EOC ) ) == 0 )
  284.         {                       /* "end of cookie"-marker */
  285.           if( lines > 0 )
  286.             {                   /* store the cookie */
  287.               /* but drop the last LF, to avoid trouble in recognizing abbrev's: */
  288.               cbuflen = strlen( cbuf );
  289.               if( cbuf[ cbuflen - 1 ] == '\n' )
  290.                 cbuf[ --cbuflen ] = '\0';
  291.               clist[ listed ].text = malloc( cbuflen + 1 );       /* mind the '\0'! */
  292.               if( clist[ listed ].text != NULL )
  293.                 {
  294.                   clist[ listed ].number = listed + ignored;
  295.                   clist[ listed ].size = cbuflen;
  296.                   strcpy( clist[ listed ].text, cbuf );
  297.                   clist[ listed ].sorthook = clist[ listed ].text;
  298.                 }
  299.               else
  300.                 {
  301.                   printf( "\nOut of memory\n" );
  302.                   exit( 20 );
  303.                 }
  304.               if( ++listed == listsize )
  305.                 {
  306.                   listsize = 3 * listsize / 2;
  307.                   clist = realloc( clist, listsize * sizeof( struct cookie ) );
  308.                   if( !clist )
  309.                     {
  310.                       printf( "\nList reallocation failed\n" );
  311.                       exit( 20 );
  312.                     }
  313.                 }
  314.             }
  315.           else
  316.             ignored++;          /* or ignore it */
  317.           /* start a new one */
  318.           strcpy( cbuf, "" );
  319.           lines = 0;
  320.           cbuflen = 0;
  321.         }
  322.       else
  323.         {
  324.           if( (cbuflen += strlen( line ) ) >= CBUFSIZE )
  325.             {
  326.               printf( "\nCookie too big( >%ld chars )\n", CBUFSIZE );
  327.               exit( 20 );
  328.             }
  329.           strcat( cbuf, line );
  330.           lines++;
  331.         }
  332.     }
  333.   printf( ", done. (%ld read, %ld empty)\n", listed, ignored );
  334. }
  335.  
  336.  
  337. /* 
  338.  * Write cookies to file, 
  339.  * also frees the allocated memory!
  340.  */
  341. void write_cookies( FILE *fp )
  342. {
  343.   long l;
  344.  
  345.   printf( "Writing cookies" );
  346.   fflush( stdout );
  347.   for( l = 0; l < listed; l++ )
  348.     {
  349.       if( fprintf( fp, "%s\n%s\n", clist[ l ].text, EOC ) <= 0 )
  350.         {
  351.           printf( "\nFile error, aborted !!!\n" );
  352.           exit( 20 );
  353.         }
  354.       free( clist[ l ].text );
  355.     }
  356.   printf( ", done. (%ld written)\n", listed );
  357. }
  358.  
  359.  
  360. int main( int argc, char *argv[] )
  361. {
  362.   UBYTE *s;
  363.   int dirty = 0, passive = 0, abbrevs = 0, finalsort = 0;
  364.   int case_sense = 0, bordermode = 2;
  365.   UBYTE name1[ 100 ], name2[ 100 ], name3[ 100 ];
  366.   FILE *infile, *outfile, *logfile;
  367.  
  368.   name1[ 0 ] = name2[ 0 ] = name3[ 0 ] = '\0';
  369.   if( argc < 2 )
  370.     {
  371.       help( NULL );
  372.       return 5;
  373.     }
  374.   while( --argc )
  375.     {
  376.       s = *++argv;
  377.       if( *s != '-' )
  378.         {
  379.           if( name1[ 0 ] == '\0' )
  380.             strcpy( name1, s );
  381.           else
  382.             strcpy( name3, s );
  383.         }
  384.       else
  385.         {
  386.           switch( *++s )
  387.             {
  388.             case 's':
  389.               switch( *++s )
  390.                 {
  391.                 case '\0':
  392.                   finalsort = 1;
  393.                   break;
  394.                 case 's':
  395.                   finalsort = 2;
  396.                   break;
  397.                 case 'l':
  398.                   finalsort = 3;
  399.                   break;
  400.                 case 'w':
  401.                   finalsort = 4;
  402.                   break;
  403.                 default:
  404.                   if( ispunct( *s ) )
  405.                     {
  406.                       finalsort = 5;
  407.                       strncpy( hooktarget, s, 15 );
  408.                     }
  409.                   else
  410.                     {
  411.                       help( argv[ 0 ] );
  412.                       return 5;
  413.                     }
  414.                 }
  415.               break;
  416.             case 'd':
  417.               if( isdigit( *++s ) )
  418.                 bordermode = atoi( s );
  419.               else
  420.                 {
  421.                   help( argv[ 0 ] );
  422.                   return 5;
  423.                 }
  424.               break;
  425.             case 'c':
  426.               case_sense = 1;
  427.               break;
  428.             case 'a':
  429.               abbrevs = 1;
  430.               break;
  431.             case 'p':
  432.               passive = 1;
  433.               break;
  434.             case 'o':
  435.               dirty = 1;
  436.               break;
  437.             default:
  438.               help( argv[ 0 ] );
  439.               return 5;
  440.             }
  441.         }
  442.     }
  443.   /* important, before calling anything from strstuff: */
  444.   str_setup( bordermode, case_sense );
  445.   if( name1[ 0 ] == '\0' )
  446.     {
  447.       help( NULL );
  448.       return 5;
  449.     }
  450.   if( dirty )
  451.     {
  452.       strcpy( name2, name1 );
  453.       printf( "Warning!  You have enabled direct writeback mode!\n" );
  454.       printf( "\e[2mDon't break (or crash) cookietool now, " );
  455.       printf( "or you will inevitably lose data!\e[0m\n" );
  456.     }
  457.   else
  458.     strcpy( name2, "ct_temp_crunchfile" );
  459.   printf( "CookieTool " );
  460.   print_strstat();
  461.   clist = malloc( listsize * sizeof( struct cookie ) );
  462.   if( !clist )
  463.     {
  464.       printf( "List allocation failed\n" );
  465.       return 20;
  466.     }
  467.   if( !(infile = fopen( name1, "r" ) ) )
  468.     {
  469.       printf( "Can't open %s for input!\n", name1 );
  470.       return 10;
  471.     }
  472.   setvbuf( infile, NULL, _IOFBF, FBUFSIZE );
  473.   if( name3[ 0 ] != '\0' )
  474.     {
  475.       if( !(logfile = fopen( name3, "w" ) ) )
  476.         {
  477.           printf( "Can't open %s for output!\n", name3 );
  478.           return 10;
  479.         }
  480.     }
  481.   else
  482.     logfile = NULL;
  483.   read_cookies( infile );
  484.   fclose( infile );
  485.   one_cookie( !passive, abbrevs, finalsort, logfile );
  486.   if( logfile )
  487.     fclose( logfile );
  488.   if( !(outfile = fopen( name2, "w" ) ) )
  489.     {
  490.       printf( "Can't open %s for output!\n", name2 );
  491.       return 10;
  492.     }
  493.   setvbuf( outfile, NULL, _IOFBF, FBUFSIZE );
  494.   write_cookies( outfile );
  495.   fclose( outfile );
  496.   free( clist );
  497.   if( !dirty )
  498.     {                           /* replace the input file */
  499.       if( remove( name1 ) != 0 || rename( name2, name1 ) != 0 )
  500.         {
  501.           printf( "Couldn't overwrite the input file!  Your cookies are in '%s'.\n", name2 );
  502.           return 5;
  503.         }
  504.     }
  505.   return 0;
  506. }
  507.  
  508.